
// The format of string resources is explained below.
//
// The smallest granularity of string resource that can be loaded/updated is a block.
// Each block is identified by an ID, starting with 1. You need to use the block ID
// when calling FindResource(), LoadResource(), UpdateResource().
// 
// A string with ID, nStringID, is in the block with ID, nBlockID, given by the following 
// formula:
//                    nBlockID = (nStringID / 16) + 1; // Note integer division.
// 
// A block of string resource is laid out as follows:
// Each block has NO_OF_STRINGS_PER_BLOCK (= 16) strings. Each string is represented as
// an ordered pair, (LENGTH, TEXT). The LENGTH is a WORD that specifies the size, in terms
// of number of characters, of the string that follows. TEXT follows the LENGTH and is 
// a sequence of UNICODE characters, NOT terminated by a NULL character.Any TEXT may be of
// zero-length, in which case, LENGTH is zero. 
// 
// An executable does not have a string table block with ID, nBlockID, if it does not have any 
// strings with IDs - ((nBlockID - 1) * 16) thru' ((nBlockID * 16) - 1).
//
// This format is the same for Windows NT, Windows 95 & Windows 98. Yes, strings in a resource 
// are internally stored in UNICODE format even in Windows 95 & Windows 98.


// Internal data structure format for a string block.
// Our block of strings has as an array of UNICODE string pointers.




// General Usage of this class:

//		1. Load string resource table from file using GetStringBlock();
//		2. Alter the stringblock using SetString()
//		3. Write the new string block back to disk using UpdateResourceBlock();

// Example:

//		CResString m_pResString;
//		m_pResString.GetStringBlock( "MyExe.exe", 3, CResString::EnglishUS );
//		m_pResString.SetString( 8, "HOW ARE YOU?" );
//		m_pResString.UpdateResourceBlock( "MyExe.exe", 3, CResString::EnglishUS );


// Internally, the class will read an entire string block from the resource table and copy it into
// its own stringblock structure. This structure is kept in memory within the class.
// When a user makes and changes the internal structure is changed only. 
// After UpdateResourceBlock() is called the internal structure is converted from an array of widechars
// back into an actual string table resource and then embedded/overwritten within the exe's resources.

// This class was modified from 'Stablupd.exe Manipulate String Resources in an Executable Q196774' article.
// Very little code was altered, other than to convert the C code into an MFC C++ Class.

//		Modified By: zebbedi 
//		Modified On: 24/01/2003
//		Version	   : v1.0
//		Contact    : support@zykial.com

// This class was again modified in order to make it more programmer friendly and to increase its efficiency.
// Instead of loading the file when a resource is accessed, a seperate method for loading a file was added.
// This was done so the file isn't loaded whenever a new resource in the same file is requested.
// New methods to enumerate the resources in a file were also added.

//		Modified By: M0tah
//		Modified On: 06/2008



// ResString.h: interface for the CResString class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_RESSTRING_H__CF2FC1BF_F005_43B7_AAF7_FF5A48846E1C__INCLUDED_)
#define AFX_RESSTRING_H__CF2FC1BF_F005_43B7_AAF7_FF5A48846E1C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

//#include "global.h"
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include <string>
#include <list>
#include <vector>
using namespace std;


// Error Codes
#define SUCCESS_MADE		 1000
#define INVALID_BLOCK		 1001
#define INSUFFICIENT_MEMORY  1002
#define RESOURCE_NOT_FOUND   1003
#define NO_LOAD_RESTABLE     1004
#define NO_BUILD_RESTABLE    1005
#define LIBRARY_LOAD_FAILED  1006
#define INVALID_BLOCK_INDEX  1007
#define UNKNOWN_ERROR		 1008
#define FAILED_WRITING_BLOCK 1009
#define INVALID_STRING		 1010
#define FILE_NOT_LOADED		 1011

// There are 16 possible string entries within a string table
#define NO_OF_STRINGS_PER_BLOCK 16	


class CResString  
{
public:
	CResString();
	CResString(string scPath);
	virtual ~CResString();

public:

	// Language ID
	enum LanguageID
	{
		EnglishUS		= MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
		EnglishUK		= MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK),
		FrenchFrance    = MAKELANGID(LANG_FRENCH, SUBLANG_FRENCH),
		GermanGermany   = MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN),
		Neutral			= MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
	};

protected:

	// Declare a new internal resource block structure for storing strings
	typedef struct tagSTRINGBLOCK
	{
		UINT		nBlockID;								// The ID of the block.
		WORD		wLangID;								// The language ID.
		LPWSTR		strArray[NO_OF_STRINGS_PER_BLOCK];		// We maintain the strings internally in UNICODE.
	} STRINGBLOCK, * PSTRINGBLOCK;

	// Declare global resource block structure for use with functions
	PSTRINGBLOCK pStrBlock;
	HINSTANCE    hInstLib;
	string scAppPath;
	// global variables for type enumeration
	vector<string> vScTypes;
	int iTypeIndex;
	bool bContainsType;
	// global variables for name enumeration
	vector<string> vScNames;
	long iNameIndex;



protected:

	// Builds a new string table resource based on the one stored within this class
	void BuildResBlock( LPVOID pRes );

	// Builds a new tagSTRINGBLOCK structure based on the string table resource loaded from file
	int BuildStringBlock( LPVOID pRes );
	
	// Deletes the internally held string table structure held in memory to avoid memory leaks
	int DeleteStringBlock();

	// Retrieves the string at nIndex and converts from widechar
	int GetString( UINT nIndex, LPSTR pszText );

	// Retrieves the wstring at nIndex
	int GetWString( UINT nIndex, LPWSTR pswzText );

	// Returns the length of a specific string
	int GetStringLength( UINT nIndex );

	// Returns the size of the entire resource structure
	DWORD GetResSize();

	// callback functions for resource enumeration
	BOOL EnumResTypes( HMODULE hModule, LPTSTR lpType, LONG lParam); 
	BOOL FindResTypeStr( HMODULE hModule, LPTSTR lpType, LONG lParam);
	BOOL FindResTypeInt( HMODULE hModule, LPTSTR lpType, LONG lParam);
	BOOL EnumResNames( HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam);

public:

	// Loads a new file to get the resources of
	void LoadFile(string scPath);

	// Change the contents of a string resource within internally held structure. Call UpdateResourceBlock to write to disk
	int SetString( UINT nIndex, string scText );

	// Retrieves/Loads the string resource table from file
	int GetStringBlock( UINT nBlockID, WORD wLangID );
	int GetStringBlock( UINT nBlockID, LanguageID langID );

	// Writes the internally held string structure to disk/file
	int UpdateResourceBlock(UINT nBlockID, WORD wLangID);
	int UpdateResourceBlock(UINT nBlockID, LanguageID langID);

	string GetString( UINT nIndex );
	wstring GetWString( UINT nIndex );


	// gets first type in preparation for resource type enumeration; returns "" if no resources found/other error occurs
	LPCSTR GetFirstType();
	// gets next type after calling GetFirstType; returns "" when there are no more types to get
	LPCSTR GetNextType();
	// checks the loaded file for resources of type strType
	bool ContainsType(LPTSTR strType);
	// checks the loaded file for resources of type iType
	bool ContainsType(USHORT iType);

	// gets first name in preparation for resource name enumeration; returns "" if no resources of specified type found/other error occurs
	LPCSTR GetFirstNameInt(USHORT iType);
	LPCSTR GetFirstNameStr(LPCTSTR strType);
	// gets next name after calling GetFirstName<Str/Int>; returns "" when there are no more names to get
	LPCSTR GetNextName();

};

#endif // !defined(AFX_RESSTRING_H__CF2FC1BF_F005_43B7_AAF7_FF5A48846E1C__INCLUDED_)
